//
//  readinput.cxx
//  Schedule
//
//  Created by Julius Canute on 2/15/12.
//  Copyright 2012 ABB. All rights reserved.
//
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/framework/XMLFormatter.hpp>
#include <xercesc/framework/StdOutFormatTarget.hpp>
#include <xercesc/framework/LocalFileFormatTarget.hpp>
#include <sys/wait.h>
#include <math.h>
#include <map>

#include "schedule.h"
#include "XMLGenerator.h"

using namespace xercesc;
using namespace std;

/*
class component;
class application;
class node;
class component;
class sequence;
class processor;
class search_space;
class application;
*/
int process_node(vector <node*> &n,vector < vector<int> > &m,vector <application> &apps,queue <search_space> &q,search_space &s,int &a_sum);


int parse_node_xml(char* xmlFile,int no,search_space &s,vector <node*> &n){

    DOMDocument *doc = 0;
    XMLCh tempStr[100];
    XMLString::transcode("LS", tempStr, 99);
    DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr);
    DOMLSParser* parser = ((DOMImplementationLS*)impl)->createLSParser(DOMImplementationLS::MODE_SYNCHRONOUS, 0);

    try {
        doc = parser->parseURI(xmlFile);
    }
    catch (const XMLException& toCatch) {
        char* message = XMLString::transcode(toCatch.getMessage());
        cout << "Exception message is: \n"
        << message << "\n";
        XMLString::release(&message);
        return -1;
    }
    catch (const DOMException& toCatch) {
        char* message = XMLString::transcode(toCatch.msg);
        cout << "Exception message is: \n"
        << message << "\n";
        XMLString::release(&message);
        return -1;
    }
    catch (...) {
        cout << "Unexpected Exception \n" ;
        return -1;
    }
     

    DOMElement *root = doc->getDocumentElement();
    XMLCh tagName[100];
    XMLString::transcode("NodeId",tagName,99);
    DOMNodeList *list = root->getElementsByTagName(tagName);
    DOMNode *t_node = list->item(0);
    char *out = XMLString::transcode(t_node->getTextContent());
    int node_no;
    {
	
        //int node_no;
	stringstream ss;
	ss<<out;
	istringstream iss(ss.str(),istringstream::in);
	iss>>node_no;
	s.p[no].node_no = node_no;
    	//cout<<"NodeId:"<<out<<endl;

    }

    cout<<"NodeId:"<<node_no<<endl;
    XMLString::release(&out);


    XMLString::transcode("CycleTime",tagName,99);
    list = root->getElementsByTagName(tagName);
    t_node = list->item(0);
    out = XMLString::transcode(t_node->getTextContent());
    int left_capacity;
    {
    
	//int left_capacity;
	stringstream ss;
	ss<<out;
	istringstream iss(ss.str(),istringstream::in);
	iss>>left_capacity;
	s.p[no].left_capacity = left_capacity;
    	//cout<<"CycleTime:"<<out<<endl;
    }

    cout<<"CycleTime:"<<left_capacity<<endl;
    XMLString::release(&out);

    XMLString::transcode("Unit",tagName,99);
    list = root->getElementsByTagName(tagName);
    t_node = list->item(0);
    out = XMLString::transcode(t_node->getTextContent());
    
    {
    	stringstream ss;
	ss<<out;
	s.p[no].unit = ss.str();
	cout<<"Unit:"<<out<<endl;
    }
    XMLString::release(&out);
    
    XMLString::transcode("OSHWTime",tagName,99);
    list = root->getElementsByTagName(tagName);
    t_node = list->item(0);
    out = XMLString::transcode(t_node->getTextContent());
    cout<<"OSHWTime:"<<out<<endl;
    XMLString::release(&out);


    XMLString::transcode("ContextSWTime",tagName,99);
    list = root->getElementsByTagName(tagName);
    t_node = list->item(0);
    out = XMLString::transcode(t_node->getTextContent());
    cout<<"ContextSWTime:"<<out<<endl;
    XMLString::release(&out);


    XMLString::transcode("ManagementTime",tagName,99);
    list = root->getElementsByTagName(tagName);
    t_node = list->item(0);
    out = XMLString::transcode(t_node->getTextContent());
    cout<<"ManagementTime:"<<out<<endl;
    XMLString::release(&out);
    

   
    n.push_back(new node(left_capacity,node_no));

    XMLString::transcode("OffsetSupported",tagName,99);
    list = root->getElementsByTagName(tagName);
    t_node = list->item(0);
    out = XMLString::transcode(t_node->getTextContent());

    {
    	stringstream ss;
    	ss<<out;
    	n.back()->offset = ss.str();
    }
    cout<<"OffsetSupported:"<<n.back()->offset<<endl;
    XMLString::release(&out);
    
    
    parser->release();
    return 0;
}


int parse_application_xml(char* xmlFile,int no,search_space &s,int &a_sum,int &nn,vector <node*> n,vector < vector<int> > &m,vector <application> &apps){

    DOMDocument *doc = 0;
    XMLCh tempStr[100];
    XMLString::transcode("LS", tempStr, 99);
    DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr);
    DOMLSParser* parser = ((DOMImplementationLS*)impl)->createLSParser(DOMImplementationLS::MODE_SYNCHRONOUS, 0);
    s.a[no] = 0;
    try {
        doc = parser->parseURI(xmlFile);
    }
    catch (const XMLException& toCatch) {
        char* message = XMLString::transcode(toCatch.getMessage());
        cout << "Exception message is: \n"
        << message << "\n";
        XMLString::release(&message);
        return -1;
    }
    catch (const DOMException& toCatch) {
        char* message = XMLString::transcode(toCatch.msg);
        cout << "Exception message is: \n"
        << message << "\n";
        XMLString::release(&message);
        return -1;
    }
    catch (...) {
        cout << "Unexpected Exception \n" ;
        return -1;
    }

    
    XMLCh tagName[100];
    XMLString::transcode("Application",tagName,99);

    DOMElement *root =(doc->getDocumentElement())->getFirstElementChild();
    XMLCh attribute[100];
    XMLString::transcode("cycle",attribute,99);
    int ca;
    char *out = XMLString::transcode(root->getAttribute(attribute));
    {
	

	stringstream ss;
	ss<<out;
	istringstream iss(ss.str(),istringstream::in);
	iss>>ca;
    	//cout<<"CycleTime Application:"<<out<<endl;
    	
    }

    cout<<"CycleTime Application:"<<ca<<endl;
    XMLString::release(&out);

    XMLString::transcode("deadline",attribute,99);
    out = XMLString::transcode(root->getAttribute(attribute));
    cout<<"Deadline:"<<out<<endl;
    XMLString::release(&out);
    
    
    
    



    XMLCh tagName1[100],tagName2[100],tagName3[100];

   
    XMLString::transcode("JobDuration",tagName1,99);
    XMLString::transcode("JobConstraint",tagName2,99);
    XMLString::transcode("CompName",tagName3,99);
    DOMNodeList *list1 = root->getElementsByTagName(tagName1);
    DOMNodeList *list2 = root->getElementsByTagName(tagName2);
    DOMNodeList *list3 = root->getElementsByTagName(tagName3);
    
    application a(ca);
    
    XMLString::transcode("unit",attribute,99);
    out = XMLString::transcode(root->getAttribute(attribute));
    {
    	string unit;
    	stringstream ss;
    	ss<<out;
    	istringstream iss(ss.str(),istringstream::in);
    	iss>>unit;
    	a.unit = unit;
    }
    cout<<"Application Time:"<<a.unit<<endl;
    XMLString::release(&out);
    
    /*This pertains to an application*/
    XMLString::transcode("appname",attribute,99);
    string application_name;
    out = XMLString::transcode(root->getAttribute(attribute));
    {
	stringstream ss;
	ss<<out;
	istringstream iss(ss.str(),istringstream::in);
	iss>>application_name;
	a.app_name = application_name;    
    }
    cout<<"Application Name:"<<application_name<<endl;
    XMLString::release(&out);
    
    /*
    for (int j=0;j<nn;j++){

    	if(ca % n[j]->cycle_time == 0)
	{
		cout<<"Application ("<<j<<") is schedulable on node ("<<no<<")"<<endl;
		a.node_list.push_back(n[j]);
		m[j].push_back(no);
	}

    }
    */
    
    int max_exec_time = 0;
    a_sum += list1->getLength();
    
    for (size_t i=0; i<list1->getLength(); i++) {

        DOMNode *t_node1 = list1->item(i);
        DOMNode *t_node2 = list2->item(i);
        DOMNode *t_node3 = list3->item(i);

	int ec;
        char *out1 = XMLString::transcode(t_node1->getTextContent());
	char *out2 = XMLString::transcode(t_node2->getTextContent());
	char *out3 = XMLString::transcode(t_node3->getTextContent());
	{

		stringstream ss;
		ss<<out1;
		istringstream iss(ss.str(),istringstream::in);
		iss>>ec;
		//a.order.push_back(component(ec,no,i));
		//cout<<"JobDuration:"<<out1<<endl;
	
	}
	cout<<"JobDuration:"<<ec<<endl;
    	max_exec_time = max(max_exec_time,ec);
	a.order.push_back(component(ec,no,i));
	cout<<"JobConstraint:"<<out2<<endl;
	
	string comp_name;
	{
		stringstream ss;
		ss<<out3;
		istringstream iss(ss.str(),istringstream::in);
		iss>>comp_name;
	}
	a.order[i].comp_name = comp_name;
	cout<<"CompName:"<<comp_name<<endl;

        XMLString::release(&out1);
        XMLString::release(&out2);
        XMLString::release(&out3);
    }
    
    
    for (int j=0;j<nn;j++){
        
    	if(ca % n[j]->cycle_time == 0)//&& max_exec_time <= n[j]->cycle_time)
        {
            
            cout<<"Application ("<<j<<") is schedulable on node ("<<no<<")"<<endl;
            a.node_list.push_back(n[j]);
            m[j].push_back(no);
             
            
        }
        
    }
    
    apps.push_back(a);



   
    XMLString::transcode("Group",tagName,99);

    DOMNodeList *list = root->getElementsByTagName(tagName);

    for (size_t i=0; i<list->getLength(); i++) {

	cout<<"Group"<<"("<<i<<"):"<<endl;
        DOMNode *t_node = list->item(i);

	DOMNodeList *child_list = t_node->getChildNodes();

	cout<<"Child Node Size:"<<child_list->getLength()<<endl;
	for(size_t j=0;j<child_list->getLength();j++)
	{
		DOMNode *child_node = child_list->item(j);
        	char *out = XMLString::transcode(child_node->getTextContent());
		if(child_node->getNodeType()==1)
			cout<<out<<endl;
        	XMLString::release(&out);
	}

    
    }
   
  

    parser->release();
    return 0;
}
int generate_graph(string fname){
 
    
    char* programPath = "/bin/sh";
    
    pid_t pid = fork(); /* Create a child process */
    
    switch (pid) {
        case -1: /* Error */
            std::cerr << "Uh-Oh! fork() failed.\n";
            exit(1);
        case 0: /* Child process */
            execl(programPath,"sh","-c","python ../visualizer/gantt.py -o schedule.gpl schedule.txt;gnuplot -e 'set term x11;set terminal postscript eps color solid;set output \"schedule.eps\";load \"schedule.gpl\";unset output;'", NULL); /* Execute the program */
            std::cerr << "Uh-Oh! execl() failed!"; /* execl doesn't return unless there's an error */
            exit(1);
        default: /* Parent process */
            std::cout << "Process created with pid " << pid << "\n";
            int status;
            
            while (!WIFEXITED(status)) {
                waitpid(pid, &status, 0); /* Wait for the process to complete */
            }
            
            std::cout << "Process exited with " << WEXITSTATUS(status) << "\n";
            
            return 0;
    }
}
void generate_text_output_host(vector <application> &apps, vector <processor> &p){
    ofstream sfile;
    sfile.open ("schedule.txt");
    for (int i=0; i<p.size(); i++) {
        for (int j=0; j<p[i].assign.size(); j++) {
            if(p[i].assign[j].app_no != -1)
            {
                sfile<<"Host"<<(i+1)<<" ";
                sfile<<p[i].assign[j].start_time<<" ";
                sfile<<(p[i].assign[j].start_time + apps[p[i].assign[j].app_no].order[p[i].assign[j].comp_no].ex_time)<<" ";
                sfile<<apps[p[i].assign[j].app_no].app_name;
                sfile<<endl;
                
            }
        }
    }
    sfile.close();
    generate_graph("schedule.txt");
}
void generate_xml_output_host(vector <application> &apps, vector <processor> &p){
    
    //Created an instance of XML Generator
    
    
    
    	//Got the root element
    	
    	
    	
            generate_text_output_host(apps,p);
            map<string,bool> s_already;
            //node = xml->addElement(node_main, "Host", NULL, true);
            //xml->addElement(node, "NodeId",ss.str().c_str(), true);
            for (int i=0; i<p.size(); i++) {
            DOMElement *node,*node_main,*t_node_main;
            XMLGenerator *xml = new XMLGenerator();
            node_main = xml->getRoot();
            node_main = xml->addElement(node_main, "sequential", NULL, true);
            	for (int j=0; j<p[i].assign.size(); j++) {
            		string comp_name,app_name;
            		if(p[i].assign[j].app_no == -1)
            			continue;
            		comp_name = apps[p[i].assign[j].app_no].order[p[i].assign[j].comp_no].comp_name;
            		app_name = apps[p[i].assign[j].app_no].app_name;
            		string actual_name = app_name + comp_name;
            		//cout<<"Trying:"<<comp_name<<endl;
                	if(s_already.find(actual_name)==s_already.end())
                	{
                    	//cout<<" APPNAME "<<apps[p[i].assign[j].app_no].app_name<<" COMPNAME "<<apps[p[i].assign[j].app_no].order[p[i].assign[j].comp_no].comp_name<<" STTIME "<<p[i].assign[j].start_time<<endl;
                    		//Application
                    		s_already.insert(pair<string,bool>(actual_name,true));
                    		int period = apps[p[i].assign[j].app_no].cycle_time/p[i].left_capacity;
                    		if(period != 1)
                    		{
                    			cout<<"Period:"<<period<<endl;
                    			{
                    				
                    				stringstream ss;
                    				ss<<period;
                    				t_node_main = xml->addElement(node_main, "periodic",NULL, true,"period",ss.str().c_str());
                    				
                    			}
                    			
                    			{
                    				
                    				float factor = ((p[i].assign[j].start_time*1.0f)/(p[i].left_capacity*1.0f));
                    				long cycle = floor(factor) + 1;
                    				cout<<"Cycle:"<<cycle<<endl;
                    				stringstream ss;
                				ss<<cycle;
                				xml->addElement(t_node_main, NULL, NULL, false,"start",ss.str().c_str());
                				
                    			}
                    		
                    		}
                    		else
                    			t_node_main = node_main;
                    		
                    		
                    		if(t_node_main == NULL)
                    			t_node_main = node_main;
                    			
                    		{
                    		
                			stringstream ss;
                			ss<<apps[p[i].assign[j].app_no].app_name;
                			node = xml->addElement(t_node_main, "execute",NULL, true,"application",ss.str().c_str());
            
                    		}
                    	
                   		//Execute
                   		/*
                   		{
                   			stringstream ss;
                   			ss<<apps[p[i].assign[j].app_no].order[p[i].assign[j].comp_no].comp_name;
                   			xml->addElement(node, "Execute",ss.str().c_str(), true);
                   		}
                   		*/
                   		{
            				stringstream ss;
           				ss<<apps[p[i].assign[j].app_no].order[p[i].assign[j].comp_no].comp_name;
            				node = xml->addElement(node, NULL, NULL, false,"component",ss.str().c_str());
        			}
                   		
                   		/*
                   		//At
                   		{
                   			stringstream ss;
                   			ss<<p[i].assign[j].start_time;
					node = xml->addElement(node_main, "execute_at",NULL, true,"offset",ss.str().c_str());
                   		}
                   		
                   		//Unit
                   		{
                   			stringstream ss;
           				ss<<p[i].unit;
            				node = xml->addElement(node, NULL, NULL, false,"unit",ss.str().c_str());
                   		}
                   		*/
                	}
            	}
            	
            //Serialize to a specific file name
            stringstream xml_name;
	    xml_name<<"ScheduleHost"<<(i+1)<<".xml";
            xml->SerializeToFile(xml_name.str().c_str());
	    delete xml;
           }
            
            
        
        
        
    
}
int main(){

    try {
        XMLPlatformUtils::Initialize();
    }
    catch (const XMLException& toCatch) {
        char* message = XMLString::transcode(toCatch.getMessage());
        cout << "Error during initialization! :\n"
        << message << "\n";
        XMLString::release(&message);
        return 1;
    }

    XMLCh tempStr[100];
    XMLString::transcode("LS", tempStr, 99);
    DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr);
    DOMLSParser* parser = ((DOMImplementationLS*)impl)->createLSParser(DOMImplementationLS::MODE_SYNCHRONOUS, 0);
    string fileName;
    cout<<"Enter a File Name to parse:"<<endl;
    cin>>fileName;
    const char* xmlFile = fileName.c_str();
    DOMDocument *doc;
    
    try {
	cout<<"Opening XML File "<<xmlFile<<endl;
        doc = parser->parseURI(xmlFile);
    }
    catch (const XMLException& toCatch) {
        char* message = XMLString::transcode(toCatch.getMessage());
        cout << "Exception message is: \n"
        << message << "\n";
        XMLString::release(&message);
        return -1;
    }
    catch (const DOMException& toCatch) {
        char* message = XMLString::transcode(toCatch.msg);
        cout << "Exception message is: \n"
        << message << "\n";
        XMLString::release(&message);
        return -1;
    }
    catch (...) {
        cout << "Unexpected Exception \n" ;
        return -1;
    }
    
    DOMElement *root = doc->getDocumentElement();
    
    XMLCh tagName[100];

    XMLString::transcode("NodeInfo",tagName,99);
    
    DOMNodeList *list = root->getElementsByTagName(tagName);


    int nn,na,nc,ca,cn,ec;
    vector< vector<int> > m;
    vector <application> apps;
    queue <search_space> q;
    vector <node*> n;
    
    nn = list->getLength();
    m.resize(nn);
    search_space s(nn);

    for (size_t i=0; i<nn; i++) {
        DOMNode *t_node = list->item(i);
        char *out = XMLString::transcode(t_node->getTextContent());
        cout<<" Node Value:"<<out<<endl;
        parse_node_xml(out,i,s,n);
        XMLString::release(&out);
    }
    
    XMLString::transcode("ApplicationInfo",tagName,99);

    list = root->getElementsByTagName(tagName);

    int a_sum = 0;
    na = list->getLength();
    s.resize_app_space(na);
    for (size_t i=0; i<na; i++) {
        DOMNode *t_node = list->item(i);
        char *out = XMLString::transcode(t_node->getTextContent());
        cout<<" Application Value:"<<out<<endl;
	parse_application_xml(out,i,s,a_sum,nn,n,m,apps);
        XMLString::release(&out);
    }

    process_node(n,m,apps,q,s,a_sum);
    parser->release();
	return 0;
}

